package notesDetection.fftPackage;

public class FftComplex {


	    private final double re;   // the real part
	    private final double im;   // the imaginary part

	    // create a new object with the given real and imaginary parts
	    public FftComplex(double real, double imag) {
	        re = real;
	        im = imag;
	    }

	    // return a string representation of the invoking Complex object
	    public String toString() {
	        if (im == 0) return re + "";
	        if (re == 0) return im + "i";
	        if (im <  0) return re + " - " + (-im) + "i";
	        return re + " + " + im + "i";
	    }

	    // return abs/modulus/magnitude and angle/phase/argument
	    public double abs()   { return Math.hypot(re, im); }  // Math.sqrt(re*re + im*im)
	    public double phase() { return Math.atan2(im, re); }  // between -pi and pi

	    // return a new Complex object whose value is (this + b)
	    public FftComplex plus(FftComplex b) {
	    	FftComplex a = this;             // invoking object
	        double real = a.re + b.re;
	        double imag = a.im + b.im;
	        return new FftComplex(real, imag);
	    }

	    // return a new Complex object whose value is (this - b)
	    public FftComplex minus(FftComplex b) {
	    	FftComplex a = this;
	        double real = a.re - b.re;
	        double imag = a.im - b.im;
	        return new FftComplex(real, imag);
	    }

	    // return a new Complex object whose value is (this * b)
	    public FftComplex times(FftComplex b) {
	    	FftComplex a = this;
	        double real = a.re * b.re - a.im * b.im;
	        double imag = a.re * b.im + a.im * b.re;
	        return new FftComplex(real, imag);
	    }

	    // scalar multiplication
	    // return a new object whose value is (this * alpha)
	    public FftComplex times(double alpha) {
	        return new FftComplex(alpha * re, alpha * im);
	    }

	    // return a new Complex object whose value is the conjugate of this
	    public FftComplex conjugate() {  return new FftComplex(re, -im); }

	    // return a new Complex object whose value is the reciprocal of this
	    public FftComplex reciprocal() {
	        double scale = re*re + im*im;
	        return new FftComplex(re / scale, -im / scale);
	    }

	    // return the real or imaginary part
	    public double re() { return re; }
	    public double im() { return im; }

	    // return a / b
	    public FftComplex divides(FftComplex b) {
	    	FftComplex a = this;
	        return a.times(b.reciprocal());
	    }

	    // return a new Complex object whose value is the complex exponential of this
	    public FftComplex exp() {
	        return new FftComplex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));
	    }

	    // return a new Complex object whose value is the complex sine of this
	    public FftComplex sin() {
	        return new FftComplex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));
	    }

	    // return a new Complex object whose value is the complex cosine of this
	    public FftComplex cos() {
	        return new FftComplex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im));
	    }

	    // return a new Complex object whose value is the complex tangent of this
	    public FftComplex tan() {
	        return sin().divides(cos());
	    }
	    


	    // a static version of plus
	    public static FftComplex plus(FftComplex a, FftComplex b) {
	        double real = a.re + b.re;
	        double imag = a.im + b.im;
	        FftComplex sum = new FftComplex(real, imag);
	        return sum;
	    }

	    public static FftComplex[] GenerateComplexArray(double[] realArray, int outputLength)
	    {
	    	FftComplex[] outArray = new FftComplex[outputLength];
	    	
			for(int sampleIndex = 0; sampleIndex < realArray.length; sampleIndex++)
			{
				outArray[sampleIndex] = new FftComplex(realArray[sampleIndex], 0);
			}
			for(int sampleIndex = realArray.length; sampleIndex < outputLength; sampleIndex++)
			{
				outArray[sampleIndex] = new FftComplex(0, 0);
			}
	    	
	    	return outArray;
	    }
	    
	    public static double[] GetAbsoluteValue(FftComplex[] complexArray)
	    {
	    	double[] outArray = new double[complexArray.length];
	    	for(int arrayIndex = 0; arrayIndex < complexArray.length; arrayIndex++)
	    	{
	    		outArray[arrayIndex] = GetAbsoluteValue(complexArray[arrayIndex]);
	    	}
	    	return outArray;
	    }
	    
		public static double GetAbsoluteValue(FftComplex fftComplex) {
			return Math.sqrt(fftComplex.re * fftComplex.re + fftComplex.im * fftComplex.im);
		}

	}
